﻿using System.Globalization;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Ewk.Math.Numerics.UnitTests
{
    [TestClass]
    public class ComplexUnitTests
    {
        [TestMethod]
        public void Complex_I_squared_is_minus_1()
        {
            var result = Complex.I*Complex.I;

            Assert.AreEqual(-1*Complex.One, result);
        }

        [TestMethod]
        public void Complex_squareRoot_minus_1_is_I()
        {
            var complex = -1*Complex.One;
            var result = Complex.Sqrt(complex);

            var real = System.Math.Round(result.Real, 14);
            var imaginary = System.Math.Round(result.Imaginary, 14);
            Assert.AreEqual(0.0, real);
            Assert.AreEqual(1.0, imaginary);
        }

        [TestMethod]
        public void Complex_multiplication_of_two_different_Complex_values_is_correct()
        {
            const int c1R = 3;
            const int c1I = 5;
            const int c2R = 7;
            const int c2I = 11;

            var complex1 = new Complex(c1R, c1I);
            var complex2 = new Complex(c2R, c2I);

            var result1 = complex1*complex2;
            var result2 = complex2*complex1;

            Assert.AreEqual(result1, result2);
            Assert.AreEqual(result1.Real, c1R * c2R - c1I * c2I);
            Assert.AreEqual(result1.Imaginary, c1R * c2I + c1I * c2R);
        }

        [TestMethod]
        public void Complex_multiplication_of_a_Complex_by_a_scalar_multiplies_the_elemenets_of_the_complex()
        {
            const int c1R = 3;
            const int c1I = 5;
            const int r = 7;

            var complex1 = new Complex(c1R, c1I);

            var result1 = complex1*r;
            var result2 = r*complex1;

            Assert.AreEqual(result1, result2);
            Assert.AreEqual(result1.Real, r * c1R);
            Assert.AreEqual(result1.Imaginary, r * c1I);
        }

        [TestMethod]
        public void Complex_multiplication_of_the_same_Complex_value_two_times_has_the_same_result_as_the_Complex_raised_to_the_power_two()
        {
            const int c1R = 3;
            const int c1I = 5;

            var complex1 = new Complex(c1R, c1I);

            var result1 = complex1*complex1;
            var result2 = Complex.Pow(complex1, 2);

            var real = System.Math.Round(result2.Real, 13);
            var imaginary = System.Math.Round(result2.Imaginary, 13);

            Assert.AreEqual(result1.Real, real,
                            string.Format("Expected {0}, Actual {1}",
                                          result1.Real.ToString("r", CultureInfo.InvariantCulture),
                                          real.ToString("r", CultureInfo.InvariantCulture)));
            Assert.AreEqual(result1.Imaginary, imaginary,
                            string.Format("Expected {0}, Actual {1}",
                                          result1.Imaginary.ToString("r", CultureInfo.InvariantCulture),
                                          imaginary.ToString("r", CultureInfo.InvariantCulture)));
        }

        [TestMethod]
        public void Complex_multiplication_of_the_same_Complex_value_five_times_has_the_same_result_as_the_Complex_raised_to_the_power_five()
        {
            const int c1R = 3;
            const int c1I = 5;

            var complex1 = new Complex(c1R, c1I);

            var result1 = complex1*complex1*complex1*complex1*complex1;
            var result2 = Complex.Pow(complex1, 5);

            var real = System.Math.Round(result2.Real, 10);
            var imaginary = System.Math.Round(result2.Imaginary, 10);

            Assert.AreEqual(result1.Real, real,
                            string.Format("Expected {0}, Actual {1}",
                                          result1.Real.ToString("r", CultureInfo.InvariantCulture),
                                          real.ToString("r", CultureInfo.InvariantCulture)));
            Assert.AreEqual(result1.Imaginary, imaginary,
                            string.Format("Expected {0}, Actual {1}",
                                          result1.Imaginary.ToString("r", CultureInfo.InvariantCulture),
                                          imaginary.ToString("r", CultureInfo.InvariantCulture)));
        }

        [TestMethod]
        public void Complex_addition_of_two_different_Complex_values_is_correct()
        {
            const int c1R = 3;
            const int c1I = 5;
            const int c2R = 7;
            const int c2I = 11;

            var complex1 = new Complex(c1R, c1I);
            var complex2 = new Complex(c2R, c2I);

            var result1 = complex1+complex2;
            var result2 = complex2+complex1;

            Assert.AreEqual(result1, result2);
            Assert.AreEqual(result1.Real, c1R + c2R);
            Assert.AreEqual(result1.Imaginary, c1I + c2I);
        }

        [TestMethod]
        public void Complex_addition_of_a_Complex_with_a_real_scalar_adds_to_the_real_elemenets_of_the_complex()
        {
            const int c1R = 3;
            const int c1I = 5;
            const int r = 7;

            var complex1 = new Complex(c1R, c1I);

            var result1 = complex1*r;
            var result2 = r*complex1;

            Assert.AreEqual(result1, result2);
            Assert.AreEqual(result1.Real, r * c1R);
            Assert.AreEqual(result1.Imaginary, r * c1I);
        }
    }
}
